#ifndef _MESH_H_
#define _MESH_H_

#ifdef _WIN32
#pragma once
#endif

/**
 * A class to load and move meshes
 *
 * 1.4.12 - Steven Hartin - Added bounding data into the displayable object.
 *
 * 04/03/2012 - Steven Hartin - Removed lots of functionality to the displayable
 *    classes. Fixed lots of problems with loading the same textures / improved
 *    efficiency.
 * 02/03/2012 - Stephen Gore - Created the class structure, implemented from 
 *                             UML
 *                           - Created the header file. 
 *                           - Defined all functions. 
 *                           - Made sure all functions and parameters that need 
 *                             to be are const. 
 */

class CMesh;

#include <map>
#include <string>
#include <sstream>
#include <vector>

#include <d3dx9.h>

#include "material.h"
#include "texture.h"
#include "texturecontainer.h"

using std::map;
using std::string;
using std::pair;
using std::stringstream;
using std::vector;

typedef struct TAngle {
    TAngle(float _fPitch, float _fYaw, float _fRoll) : 
                 fPitch(_fPitch), fYaw(_fYaw), fRoll(_fRoll) {}

    float fPitch;
    float fYaw;
    float fRoll;
} TAngle;

typedef struct TTriangle {
    D3DXVECTOR3 *vecarrVertices[3];
    D3DXVECTOR3 vecNormal;
} TTriangle;

typedef struct TBoundingShape
{
    D3DXVECTOR3 vecMinBound;
    D3DXVECTOR3 vecMaxBound;
    D3DXVECTOR3 vecSphereCentre;
    float fRadius;
} TBoundingShape;

class CMesh
{
public:
    // Constructor.
    CMesh();  
    // Destuctor.
    ~CMesh();                         

    // Mesh settings
    HRESULT loadMesh(LPDIRECT3DDEVICE9 device, LPCTSTR filename);   
    void loadMesh(LPD3DXMESH pMesh);
    void setMaterial(CMaterial Material, DWORD dwSubset);
    void setTexture(CTexture* texture, DWORD dwSubset);

    void render(DWORD nSubset, LPDIRECT3DDEVICE9 pDevice) const;

    const DWORD getSubsetCount() const;

    bool hasMaterial(DWORD nSubset) const;
    const CMaterial& getMaterial(DWORD nSubset) const;

    bool hasTexture(DWORD nSubset) const;
    CTexture *getTexture(DWORD nSubset) const;

    const TBoundingShape &getBoundingShape() const;

private:
    // Mesh.
    LPD3DXMESH m_pMesh;

    // list of Materials.
    map<DWORD,CMaterial> m_arrMeshMaterials;
    // List of Textures.
    map<DWORD,CTexture*> m_arrMeshTextures;
    
    // number of materials. 
    DWORD m_dwNumMaterials;

    vector<TTriangle> m_arrPlaneData;
    vector<D3DXVECTOR3*> m_arrVertices;

    TBoundingShape m_Shape;

    void _fetchVertexData();
    void _calculateBoundingSphere();
    void _calculateBoundingBox();
};

#endif